home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / libwww2 / HTTCP.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  14.9 KB  |  652 lines

  1. /*            Generic Communication Code        HTTCP.c
  2. **            ==========================
  3. **
  4. **    This code is in common between client and server sides.
  5. **
  6. **    16 Jan 92  TBL    Fix strtol() undefined on CMU Mach.
  7. **    25 Jun 92  JFG    Added DECNET option through TCP socket emulation.
  8. */
  9.  
  10. /* SOCKS mods by:
  11.  * Ying-Da Lee, <ylee@syl.dl.nec.com>
  12.  * NEC Systems Laboratory
  13.  * C&C Software Technology Center
  14.  */
  15.  
  16. #include "HTUtils.h"
  17. #include "HTParse.h"
  18. #include "HTAlert.h"
  19. #include "HTAccess.h"
  20. #include "tcp.h"                /* Defines SHORT_NAMES if necessary */
  21. #ifdef SHORT_NAMES
  22. #define HTInetStatus        HTInStat
  23. #define HTInetString        HTInStri
  24. #define HTParseInet        HTPaInet
  25. #endif
  26.  
  27. #ifdef __STDC__
  28. #include <stdlib.h>
  29. #endif
  30.  
  31. /* #define TRACE 1 */
  32.  
  33. #if defined(SVR4) && !defined(SCO) && !defined(linux)
  34. #include <sys/filio.h>
  35. #endif
  36.  
  37. /* Apparently needed for AIX 3.2. */
  38. #ifndef FD_SETSIZE
  39. #define FD_SETSIZE 256
  40. #endif
  41.  
  42. /*    Module-Wide variables
  43. */
  44.  
  45. PRIVATE char *hostname=0;        /* The name of this host */
  46.  
  47.  
  48. /*    PUBLIC VARIABLES
  49. */
  50.  
  51. /* PUBLIC SockA HTHostAddress; */    /* The internet address of the host */
  52.                     /* Valid after call to HTHostName() */
  53.  
  54. /*    Encode INET status (as in sys/errno.h)              inet_status()
  55. **    ------------------
  56. **
  57. ** On entry,
  58. **    where        gives a description of what caused the error
  59. **    global errno    gives the error number in the unix way.
  60. **
  61. ** On return,
  62. **    returns     a negative status in the unix way.
  63. */
  64. #ifndef _AMIGA
  65. #ifndef errno
  66. extern int errno;
  67. #endif /* errno */
  68.  
  69. extern char *sys_errlist[];        /* see man perror on cernvax */
  70. extern int sys_nerr;
  71. #endif /* _AMIGA */
  72. #ifdef _AMIGA
  73.  #define ioctl(s,f,v) IoctlSocket(s,f,v)
  74. #endif
  75.  
  76. #ifndef _DNET
  77. /*    Report Internet Error
  78. **    ---------------------
  79. */
  80. #ifdef __STDC__
  81. PUBLIC int HTInetStatus(char *where)
  82. #else
  83. PUBLIC int HTInetStatus(where)
  84.     char    *where;
  85. #endif
  86. {
  87.     CTRACE(tfp, "TCP: Error %d in `errno' after call to %s() failed.\n\t%s\n",
  88.         errno,  where,
  89. #ifdef _AMIGA
  90. #ifdef _AS225
  91.         strerror (errno));
  92. #else
  93.        "Unknown error" );
  94. #endif
  95. #else
  96.         errno < sys_nerr ? sys_errlist[errno] : "Unknown error" );
  97. #endif
  98.     return -1;
  99. }
  100.  
  101.  
  102. /*    Parse a cardinal value                       parse_cardinal()
  103. **    ----------------------
  104. **
  105. ** On entry,
  106. **    *pp        points to first character to be interpreted, terminated by
  107. **            non 0:9 character.
  108. **    *pstatus    points to status already valid
  109. **    maxvalue    gives the largest allowable value.
  110. **
  111. ** On exit,
  112. **    *pp        points to first unread character
  113. **    *pstatus    points to status updated iff bad
  114. */
  115.  
  116. PUBLIC unsigned int HTCardinal ARGS3
  117.     (int *,     pstatus,
  118.     char **,    pp,
  119.     unsigned int,    max_value)
  120. {
  121.     int   n;
  122.     if ( (**pp<'0') || (**pp>'9')) {        /* Null string is error */
  123.     *pstatus = -3;    /* No number where one expeceted */
  124.     return 0;
  125.     }
  126.  
  127.     n=0;
  128.     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
  129.  
  130.     if (n>max_value) {
  131.     *pstatus = -4;    /* Cardinal outside range */
  132.     return 0;
  133.     }
  134.  
  135.     return n;
  136. }
  137.  
  138.  
  139. /*    Produce a string for an Internet address
  140. **    ----------------------------------------
  141. **
  142. ** On exit,
  143. **    returns a pointer to a static string which must be copied if
  144. **        it is to be kept.
  145. */
  146.  
  147. PUBLIC CONST char * HTInetString ARGS1(SockA*,sin)
  148. {
  149.     static char string[16];
  150.     sprintf(string, "%d.%d.%d.%d",
  151.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  152.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  153.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  154.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  155.     return string;
  156. }
  157.  
  158.  
  159. /*    Parse a network node address and port
  160. **    -------------------------------------
  161. **
  162. ** On entry,
  163. **    str    points to a string with a node name or number,
  164. **        with optional trailing colon and port number.
  165. **    sin    points to the binary internet or decnet address field.
  166. **
  167. ** On exit,
  168. **    *sin    is filled in. If no port is specified in str, that
  169. **        field is left unchanged in *sin.
  170. */
  171. PUBLIC int HTParseInet ARGS2(SockA *,sin, CONST char *,str)
  172. {
  173.   char *port;
  174.   char host[256];
  175.   struct hostent  *phost;    /* Pointer to host - See netdb.h */
  176.   int numeric_addr;
  177.   char *tmp;
  178.  
  179.   static char *cached_host = NULL;
  180.   static char *cached_phost_h_addr = NULL;
  181.   static int cached_phost_h_length = 0;
  182.  
  183.   strcpy(host, str);        /* Take a copy we can mutilate */
  184.  
  185.   /* Parse port number if present */
  186.   if (port=strchr(host, ':'))
  187.     {
  188.       *port++ = 0;        /* Chop off port */
  189.       if (port[0]>='0' && port[0]<='9')
  190.     {
  191.       sin->sin_port = htons(atol(port));
  192.     }
  193.     }
  194.  
  195.   /* Parse host number if present. */
  196.   numeric_addr = 1;
  197.   for (tmp = host; *tmp; tmp++)
  198.     {
  199.       /* If there's a non-numeric... */
  200.       if ((*tmp < '0' || *tmp > '9') && *tmp != '.')
  201.     {
  202.       numeric_addr = 0;
  203.       goto found_non_numeric_or_done;
  204.     }
  205.     }
  206.  
  207.  found_non_numeric_or_done:
  208.   if (numeric_addr)
  209.     {    /* Numeric node address: */
  210.       sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
  211.     }
  212.   else
  213.     {            /* Alphanumeric node name: */
  214.       if (cached_host && (strcmp (cached_host, host) == 0))
  215.     {
  216. #if 0
  217.       fprintf (stderr, "=-= Matched '%s' and '%s', using cached_phost.\n",
  218.            cached_host, host);
  219. #endif
  220.       memcpy(&sin->sin_addr, cached_phost_h_addr, cached_phost_h_length);
  221.     }
  222.       else
  223.     {
  224. #if 0
  225.       fprintf (stderr, "=+= Fetching on '%s'\n", host);
  226. #endif
  227.       phost = gethostbyname (host);
  228.       if (!phost)
  229.         {
  230.           if (TRACE)
  231.         fprintf
  232.           (stderr,
  233.            "HTTPAccess: Can't find internet node name `%s'.\n",host);
  234.           return -1;  /* Fail? */
  235.         }
  236.  
  237.       /* Free previously cached strings. */
  238.       if (cached_host)
  239.         free (cached_host);
  240.       if (cached_phost_h_addr)
  241.         free (cached_phost_h_addr);
  242.  
  243.       /* Cache new stuff. */
  244.       cached_host = strdup (host);
  245.       cached_phost_h_addr = calloc (phost->h_length + 1, 1);
  246.       memcpy (cached_phost_h_addr, phost->h_addr, phost->h_length);
  247. #if 0
  248.       cached_phost_h_addr = strdup (phost->h_addr);
  249. #endif
  250.       cached_phost_h_length = phost->h_length;
  251.  
  252.       memcpy(&sin->sin_addr, phost->h_addr, phost->h_length);
  253.     }
  254.     }
  255.  
  256.   if (TRACE)
  257.     fprintf(stderr,
  258.         "TCP: Parsed address as port %d, IP address %d.%d.%d.%d\n",
  259.         (int)ntohs(sin->sin_port),
  260.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  261.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  262.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  263.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  264.  
  265.   return 0;    /* OK */
  266. }
  267.  
  268.  
  269. /*    Derive the name of the host on which we are
  270. **    -------------------------------------------
  271. **
  272. */
  273. #ifdef __STDC__
  274. PRIVATE void get_host_details(void)
  275. #else
  276. PRIVATE void get_host_details()
  277. #endif
  278.  
  279. #ifndef MAXHOSTNAMELEN
  280. #define MAXHOSTNAMELEN 64        /* Arbitrary limit */
  281. #endif
  282.  
  283. {
  284.     char name[MAXHOSTNAMELEN+1];    /* The name of this host */
  285. #ifdef NEED_HOST_ADDRESS        /* no -- needs name server! */
  286.     struct hostent * phost;        /* Pointer to host -- See netdb.h */
  287. #endif
  288.     int namelength = sizeof(name);
  289.  
  290.     if (hostname) return;        /* Already done */
  291.     gethostname(name, namelength);    /* Without domain */
  292.     CTRACE(tfp, "TCP: Local host name is %s\n", name);
  293.     StrAllocCopy(hostname, name);
  294.  
  295. #ifdef NEED_HOST_ADDRESS        /* no -- needs name server! */
  296.     phost=gethostbyname(name);        /* See netdb.h */
  297.     if (!phost) {
  298.     if (TRACE) fprintf(stderr,
  299.         "TCP: Can't find my own internet node address for `%s'!!\n",
  300.         name);
  301.     return;  /* Fail! */
  302.     }
  303.     StrAllocCopy(hostname, phost->h_name);
  304.     memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
  305.     if (TRACE) fprintf(stderr, "     Name server says that I am `%s' = %s\n",
  306.         hostname, HTInetString(&HTHostAddress));
  307. #endif
  308. }
  309. #endif /* !_DNET */
  310.  
  311. #ifdef __STDC__
  312. PUBLIC char * HTHostName(void)
  313. #else
  314. PUBLIC char * HTHostName()
  315. #endif
  316. {
  317. #ifndef _DNET
  318.     get_host_details();
  319.     return hostname;
  320. #else
  321.     return hostname="localhost";
  322. #endif
  323. }
  324.  
  325. #ifdef SOCKS
  326. struct in_addr SOCKS_ftpsrv;
  327. #endif
  328.  
  329.  
  330. PUBLIC int HTDoConnect (char *url, char *protocol, int default_port, int *s)
  331. {
  332. #ifndef _DNET
  333.   struct sockaddr_in soc_address;
  334.   struct sockaddr_in *sin = &soc_address;
  335.   int status;
  336.  
  337.   /* Set up defaults: */
  338.   sin->sin_family = AF_INET;
  339.   sin->sin_port = htons(default_port);
  340.  
  341.   /* Get node name and optional port number: */
  342.   {
  343.     char line[256];
  344.     char *p1 = HTParse(url, "", PARSE_HOST);
  345.     int status;
  346.  
  347.     sprintf (line, "Looking up %s.", p1);
  348.     HTProgress (line);
  349.  
  350.     status = HTParseInet(sin, p1);
  351.     if (status)
  352.       {
  353.     sprintf (line, "Unable to locate remote host %s.", p1);
  354.     HTProgress(line);
  355.     free (p1);
  356.     return HT_NO_DATA;
  357.       }
  358.  
  359.     sprintf (line, "Making %s connection to %s.", protocol, p1);
  360.     HTProgress (line);
  361.     free (p1);
  362.   }
  363.  
  364.   /* Now, let's get a socket set up from the server for the data: */
  365.   *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  366.  
  367. #ifdef SOCKS
  368.   /* SOCKS can't yet deal with non-blocking connect request */
  369.   HTClearActiveIcon();
  370.   status = Rconnect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  371.   if ((status == 0) && (strcmp(protocol, "FTP") == 0))
  372.      SOCKS_ftpsrv.s_addr = soc_address.sin_addr.s_addr;
  373.   {
  374.     int intr;
  375.     intr = HTCheckActiveIcon(1);
  376.     if (intr)
  377.       {
  378.     if (TRACE)
  379.       fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
  380.     status = HT_INTERRUPTED;
  381.     errno = EINTR;
  382.       }
  383.   }
  384.   return status;
  385. #else /* SOCKS not defined */
  386.  
  387.  
  388.   /*
  389.    * Make the socket non-blocking, so the connect can be canceled.
  390.    * This means that when we issue the connect we should NOT
  391.    * have to wait for the accept on the other end.
  392.    */
  393.   {
  394.     int ret;
  395.     int val = 1;
  396.     char line[256];
  397.  
  398.     ret = ioctl(*s, FIONBIO, &val);
  399.     if (ret == -1)
  400.       {
  401.     sprintf (line, "Could not make connection non-blocking.");
  402.     HTProgress(line);
  403.       }
  404.   }
  405.   HTClearActiveIcon();
  406.  
  407.   /*
  408.    * Issue the connect.  Since the server can't do an instantaneous accept
  409.    * and we are non-blocking, this will almost certainly return a negative
  410.    * status.
  411.    */
  412.   status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  413.  
  414.   /*
  415.    * According to the Sun man page for connect:
  416.    *     EINPROGRESS         The socket is non-blocking and the  con-
  417.    *                 nection cannot be completed immediately.
  418.    *                 It is possible to select(2) for  comple-
  419.    *                 tion  by  selecting the socket for writ-
  420.    *                 ing.
  421.    * According to the Motorola SVR4 man page for connect:
  422.    *     EAGAIN          The socket is non-blocking and the  con-
  423.    *                 nection cannot be completed immediately.
  424.    *                 It is possible to select for  completion
  425.    *                 by  selecting  the  socket  for writing.
  426.    *                 However, this is only  possible  if  the
  427.    *                 socket  STREAMS  module  is  the topmost
  428.    *                 module on    the  protocol  stack  with  a
  429.    *                 write  service  procedure.  This will be
  430.    *                 the normal case.
  431.    */
  432. #ifdef SVR4
  433.   if ((status < 0) && ((errno == EINPROGRESS)||(errno == EAGAIN)))
  434. #else
  435.   if ((status < 0) && (errno == EINPROGRESS))
  436. #endif /* SVR4 */
  437.     {
  438.       struct timeval timeout;
  439.       int ret;
  440.  
  441.       timeout.tv_sec = 0;
  442.       timeout.tv_usec = 100000;
  443.       ret = 0;
  444.       while (ret <= 0)
  445.     {
  446.       fd_set writefds;
  447.       int intr;
  448.  
  449.       FD_ZERO(&writefds);
  450.       FD_SET(*s, &writefds);
  451. #ifdef __hpux
  452.       ret = select(FD_SETSIZE, NULL, (int *)&writefds, NULL, &timeout);
  453. #else
  454.       ret = select(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
  455. #endif
  456.       /*
  457.        * Again according to the Sun and Motorola man pagse for connect:
  458.        *     EALREADY         The socket is non-blocking and a  previ-
  459.        *                 ous  connection attempt has not yet been
  460.        *                 completed.
  461.        * Thus if the errno is NOT EALREADY we have a real error, and
  462.        * should break out here and return that error.
  463.        * Otherwise if it is EALREADY keep on trying to complete the
  464.        * connection.
  465.        */
  466.       if ((ret < 0)&&(errno != EALREADY))
  467.         {
  468.           status = ret;
  469.           break;
  470.         }
  471.       else if (ret > 0)
  472.         {
  473.           /*
  474.            * Extra check here for connection success, if we try to connect
  475.            * again, and get EISCONN, it means we have a successful
  476.            * connection.
  477.            */
  478.           status = connect(*s, (struct sockaddr*)&soc_address,
  479.                    sizeof(soc_address));
  480.           if ((status < 0)&&(errno == EISCONN))
  481.         {
  482.           status = 0;
  483.         }
  484.           break;
  485.         }
  486.       /*
  487.        * The select says we aren't ready yet.
  488.        * Try to connect again to make sure.  If we don't get EALREADY
  489.        * or EISCONN, something has gone wrong.  Break out and report it.
  490.        * For some reason SVR4 returns EAGAIN here instead of EALREADY,
  491.        * even though the man page says it should be EALREADY.
  492.        */
  493.       else
  494.         {
  495.           status = connect(*s, (struct sockaddr*)&soc_address,
  496.                    sizeof(soc_address));
  497. #ifdef SVR4
  498.           if ((status < 0)&&(errno != EALREADY)&&(errno != EAGAIN)&&
  499.             (errno != EISCONN))
  500. #else
  501.           if ((status < 0)&&(errno != EALREADY)&&(errno != EISCONN))
  502. #endif /* SVR4 */
  503.         {
  504.           break;
  505.         }
  506.         }
  507.       intr = HTCheckActiveIcon(1);
  508.       if (intr)
  509.         {
  510.           if (TRACE)
  511.         fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
  512.           status = HT_INTERRUPTED;
  513.           errno = EINTR;
  514.           break;
  515.         }
  516.     }
  517.     }
  518.  
  519.   /*
  520.    * Make the socket blocking again on good connect
  521.    */
  522.   if (status >= 0)
  523.     {
  524.       int ret;
  525.       int val = 0;
  526.       char line[256];
  527.  
  528.       ret = ioctl(*s, FIONBIO, &val);
  529.       if (ret == -1)
  530.     {
  531.       sprintf (line, "Could not restore socket to blocking.");
  532.       HTProgress(line);
  533.     }
  534.     }
  535.   /*
  536.    * Else the connect attempt failed or was interrupted.
  537.    * so close up the socket.
  538.    */
  539.   else
  540.     {
  541.     close(*s);
  542.     }
  543.  
  544.   return status;
  545. #endif /* #ifdef SOCKS */
  546. #else /* _DNET */
  547.  
  548.   char host[256];
  549.   char *port;
  550.  
  551.   strcpy(host,HTParse(url,"", PARSE_HOST)); /* Be Nice :) */
  552.   port=strchr(host,':');
  553.   if (port) {
  554.     *port++=0;
  555.     if (strlen(port)==0)
  556.       sprintf(port,"%d",default_port);  /* Don't ask - Don't tell */
  557.   }
  558.   else {
  559.     port=host+strlen(host)+1;
  560.     sprintf(port,"%d",default_port);
  561.   }
  562.  
  563.   *s=DOpen(8399,25,25); /* High Priority */
  564.   if (*s==NULL) {
  565.     errno=0;
  566.     return -1;
  567.   }
  568.   {
  569. /* Put Host name */
  570.     unsigned char len;
  571.     len=strlen(host)+1;
  572.     if ((DWrite(*s,&len,1)!=1) ||
  573.     (DWrite(*s,host,len)!=len)) {
  574.       /* ?? Error */
  575.       errno=42;
  576.       DClose(*s);
  577.       *s=0;
  578.       return -1;
  579.     }
  580. /* Put port # */
  581.     len=strlen(port)+1;
  582.     if ((DWrite(*s,&len,1)!=1) ||
  583.     (DWrite(*s,port,len)!=len)) {
  584.       /* ?? Error */
  585.       errno=43;
  586.       DClose(*s);
  587.       *s=0;
  588.       return -1;
  589.     }
  590. /* Get Result */
  591.     if ((DRead(*s,&len,1)!=1) ||
  592.     (DRead(*s,host,len)!=len)) {
  593.       /* ?? Error */
  594.       errno=44;
  595.       DClose(*s);
  596.       *s=0;
  597.       return -1;
  598.     }
  599.   }
  600.   if (atoi(host)) {
  601.     errno=atoi(host);
  602.     DClose(*s);
  603.     *s=0;
  604.     return -1;
  605.   }
  606.   return 0;
  607. #endif
  608. }
  609.  
  610. #ifndef _AMIGA
  611. /* This is so interruptible reads can be implemented cleanly. */
  612. int HTDoRead (int fildes, void *buf, unsigned nbyte)
  613. {
  614.   int ready, ret, intr;
  615.   fd_set readfds;
  616.   struct timeval timeout;
  617.  
  618.   timeout.tv_sec = 0;
  619.   timeout.tv_usec = 100000;
  620.  
  621.   ready = 0;
  622.   while (!ready)
  623.     {
  624.     FD_ZERO(&readfds);
  625.     FD_SET(fildes, &readfds);
  626. #ifdef __hpux
  627.     ret = select(FD_SETSIZE, (int *)&readfds, NULL, NULL, &timeout);
  628. #else
  629.     ret = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
  630. #endif
  631.     if (ret < 0)
  632.       {
  633.         return -1;
  634.       }
  635.     else if (ret > 0)
  636.       {
  637.         ready = 1;
  638.       }
  639.     else
  640.       {
  641.         intr = HTCheckActiveIcon(1);
  642.         if (intr)
  643.           {
  644.             return HT_INTERRUPTED;
  645.           }
  646.       }
  647.     }
  648.  
  649.   return read (fildes, buf, nbyte);
  650. }
  651. #endif
  652.